

package top.continew.admin.rpc;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.shengchao.examstar.rpc.question.api.IQuestionRpc;
import com.shengchao.examstar.rpc.question.enums.QuestionSetTypeEnum;
import com.shengchao.examstar.rpc.question.req.DoQuestionReq;
import com.shengchao.examstar.rpc.question.resp.LineOptions;
import com.shengchao.examstar.rpc.question.resp.QuestionInfoResp;
import com.shengchao.examstar.rpc.question.resp.QuestionListResp;
import com.shengchao.examstar.rpc.question.resp.QuestionSelectDto;
import org.apache.dubbo.config.annotation.DubboService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.continew.admin.common.context.UserContextHolder;
import top.continew.admin.question.model.question.Question;
import top.continew.admin.question.model.question.QuestionExt;
import top.continew.admin.question.model.question.QuestionKnowledgePoint;
import top.continew.admin.question.model.question.UserDoQuestion;
import top.continew.admin.question.user.service.IQuestionService;
import top.continew.admin.question.user.service.IUserQuestionService;
import top.continew.admin.question.user.service.question.entity.*;
import top.continew.admin.question.user.service.question.enums.ProblemStateEnum;
import top.continew.admin.question.user.service.question.factory.QuestionFactory;
import top.continew.admin.question.user.service.questionset.entity.AbstractQuestionSet;
import top.continew.admin.question.user.service.questionset.factory.QuestionSetFactory;
import top.continew.starter.core.validation.ValidationUtils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Service
@DubboService

public class QuestionRpc implements IQuestionRpc {

    @Autowired
    private IQuestionService iQuestionService;

    @Autowired
    private IUserQuestionService iUserQuestionService;

    @Override
    public List<QuestionListResp> getQuestionListByQuestionSetId(String questionSetId) throws ExecutionException, InterruptedException {
        AbstractQuestionSet questionSet = QuestionSetFactory.of(questionSetId);
        if (questionSet == null) {
            return List.of();
        }
        questionSetId = String.valueOf(questionSet.getQuestionSet().getId());
        Long userLoginId = UserContextHolder.getUserId();
        Executor executor = Executors.newVirtualThreadPerTaskExecutor();
        String finalQuestionSetId = questionSetId;
        CompletableFuture<List<UserDoQuestion>> userDoQuestionsFuture = CompletableFuture
            .supplyAsync(() -> iUserQuestionService.getListByUserId(userLoginId, finalQuestionSetId), executor);

        //获取所有关联知识点的题目id
        List<Long> questionIdList = questionSet.getQuestionIdList();
        //获取题目信息
        List<AbstractQuestion> questionList = iQuestionService.getQuestionList(questionIdList);
        if (questionList.isEmpty()) {
            return List.of();
        }
        List<QuestionListResp> questionListResps = new ArrayList<>(questionList.size());
        // 批量获取所有知识点
        List<Long> allQuestionIds = questionList.stream().map(AbstractQuestion::getId).collect(Collectors.toList());
        Map<Long, List<QuestionKnowledgePoint>> allKnowledgePointsMap = new QuestionKnowledgePoint().selectList(Wrappers
            .lambdaQuery(QuestionKnowledgePoint.class)
            .in(QuestionKnowledgePoint::getQuestionId, allQuestionIds)
            .select(QuestionKnowledgePoint::getId, QuestionKnowledgePoint::getName, QuestionKnowledgePoint::getQuestionId, QuestionKnowledgePoint::getKnowledgeId))
            .stream()
            .collect(Collectors.groupingBy(QuestionKnowledgePoint::getQuestionId));

        //组装题目
        for (AbstractQuestion question : questionList) {
            questionListResps.addAll(getQuestionListResp(question, allKnowledgePointsMap));
        }
        //序号
        for (int i = 0; i < questionListResps.size(); i++) {
            QuestionListResp questionListResp = questionListResps.get(i);
            questionListResp.setQuestionNumber(String.valueOf(i + 1));
        }
        List<UserDoQuestion> userDoQuestions = userDoQuestionsFuture.get();
        //用户做题
        return setProblemStates(questionListResps, userDoQuestions);
    }

    private List<QuestionListResp> setProblemStates(List<QuestionListResp> questionListResps,
                                                    List<UserDoQuestion> userDoQuestions) {
        Map<Long, Optional<UserDoQuestion>> questionMap = userDoQuestions.stream()
            .collect(Collectors.groupingBy(UserDoQuestion::getQuestionId, Collectors.reducing((a, b) -> b)));
        questionListResps.forEach(questionListResp -> {
            Optional<UserDoQuestion> optionalUserDoQuestion = questionMap.get(questionListResp.getId());
            questionListResp.setProblemState(optionalUserDoQuestion != null && optionalUserDoQuestion.isPresent()
                ? optionalUserDoQuestion.get().getProblemState()
                : ProblemStateEnum.UNDO.getCode());
            questionListResp.setUserAnswer(optionalUserDoQuestion != null && optionalUserDoQuestion.isPresent()
                ? optionalUserDoQuestion.get().getUserAnswer()
                : "");
        });
        return questionListResps;
    }

    @NotNull
    public static List<QuestionListResp> getQuestionListResp(AbstractQuestion question,
                                                             Map<Long, List<QuestionKnowledgePoint>> allKnowledgePointsMap) {
        if (question instanceof MaterialQuestion materialQuestion) {
            return materialQuestion.getSubQuestion().stream().peek(abstractQuestion -> {
                abstractQuestion.setMaterial(materialQuestion.getMaterial());
                abstractQuestion.setKnowledgePoints(materialQuestion.getKnowledgePoints());
                abstractQuestion.setSource(materialQuestion.getSource());
                abstractQuestion.setDifficultyLevel(materialQuestion.getDifficultyLevel());
            })
                .flatMap(abstractQuestion -> getQuestionListResp(abstractQuestion, allKnowledgePointsMap).stream())
                .collect(Collectors.toList());
        }

        QuestionListResp questionListResp = new QuestionListResp();
        questionListResp.setDifficultyLevel(question.getDifficultyLevel());
        questionListResp.setId(question.getId());
        questionListResp.setAnswer(question.getAnswer());
        questionListResp.setType(String.valueOf(question.getType()));
        questionListResp.setTitle(question.getTitle());
        questionListResp.setMaterial(question.getMaterial());
        questionListResp.setTypeName(question.getTypeName());
        questionListResp.setBlankSum("0");
        questionListResp.setSpecificationType(question.getSpecificationType());

        if (question instanceof ISelectQuestion selectQuestion) {
            questionListResp.setSelect(selectQuestion.getSelect().stream().map(item -> {
                QuestionSelectDto dto = new QuestionSelectDto();
                dto.setSelectNo(item.getSelectNo());
                dto.setContent(item.getContent());
                return dto;
            }).toList());
        }

        if (question instanceof FillInTheBlankQuestion fillInTheBlankQuestion) {
            questionListResp.setBlankSum(String.valueOf(fillInTheBlankQuestion.getBlankSum()));
        }

        if (question instanceof LinkQuestion linkQuestion) {
            questionListResp.setLineOptions(JSON.parseObject(linkQuestion.getLineOptions(), LineOptions.class));
        }
        //填充知识点 - 优化版：从传入的Map中获取
        List<QuestionKnowledgePoint> questionKnowledgePoints = allKnowledgePointsMap.getOrDefault(question
            .getId(), Collections.emptyList());

        List<QuestionListResp.Knowledge> knowledgeList = new ArrayList<>(questionKnowledgePoints.size());
        for (QuestionKnowledgePoint item : questionKnowledgePoints) {
            QuestionListResp.Knowledge knowledge = new QuestionListResp.Knowledge();
            knowledge.setId(item.getKnowledgeId());
            knowledge.setKnowledgeName(item.getName());
            knowledgeList.add(knowledge);
        }
        questionListResp.setKnowledgePoints(knowledgeList);
        return List.of(questionListResp);
    }

    @Override
    public QuestionInfoResp getQuestionInfo(Long questionId, Long questionSetId) {
        Long loginId = UserContextHolder.getUserId();
        Executor executor = Executors.newVirtualThreadPerTaskExecutor();

        return CompletableFuture.supplyAsync(() -> initQuestion(questionId), executor)
            .thenCombine(CompletableFuture
                .supplyAsync(() -> initUserQuestion(questionId, questionSetId, loginId), executor), (questionInfo,
                                                                                                     userQuestionInfo) -> {
                    QuestionInfoResp response = new QuestionInfoResp();
                    if (questionInfo != null) {
                        response.setAnalysis(questionInfo.getAnalysis());
                        response.setAnswer(questionInfo.getAnswer());
                        response.setKnowledgePoints(questionInfo.getKnowledgePoints());
                        response.setSource(questionInfo.getSource());
                        response.setDifficultyLevel(questionInfo.getDifficultyLevel());
                        response.setId(questionInfo.getId());
                        response.setScore(questionInfo.getScore());
                    }
                    if (userQuestionInfo != null) {
                        response.setProblemState(userQuestionInfo.getProblemState());
                        response.setUserAnswer(userQuestionInfo.getUserAnswer());
                        response.setType(String.valueOf(userQuestionInfo.getType()));
                        response.setUserScore(userQuestionInfo.getUserScore());
                        response.setComments(userQuestionInfo.getComments());
                    }
                    return response;
                })
            .join();
    }

    private QuestionInfoResp initUserQuestion(Long questionId, Long questionSetId, Long loginId) {
        AbstractQuestionSet abstractQuestionSet = QuestionSetFactory.of(questionSetId);
        if (abstractQuestionSet == null) {
            return null;
        }
        questionSetId = abstractQuestionSet.getQuestionSet().getId();
        QuestionInfoResp questionInfoResp = new QuestionInfoResp();
        UserDoQuestion user = iUserQuestionService.getInfo(loginId, questionId, questionSetId);
        if (user != null) {
            questionInfoResp.setUserAnswer(user.getUserAnswer());
            questionInfoResp.setProblemState(user.getProblemState());
            questionInfoResp.setType(String.valueOf(user.getUserAnswerType()));
            questionInfoResp.setUserScore(user.getScore());
            questionInfoResp.setComments(user.getComments());
        }
        return questionInfoResp;
    }

    private QuestionInfoResp initQuestion(Long questionId) {
        QuestionInfoResp questionInfoResp = new QuestionInfoResp();
        Question question = new Question().selectById(questionId);
        AbstractQuestion abstractQuestion = QuestionFactory.createQuestion(question);
        abstractQuestion.initKnowledgePoints();
        ValidationUtils.throwIfEmpty(abstractQuestion, "题目不存在");
        questionInfoResp.setId(abstractQuestion.getId());
        questionInfoResp.setAnswer(abstractQuestion.getAnswer());
        questionInfoResp.setDifficultyLevel(String.valueOf(abstractQuestion.getDifficultyLevel()));
        questionInfoResp.setAnalysis(abstractQuestion.getAnalysis());
        questionInfoResp.setKnowledgePoints(abstractQuestion.getKnowledgePoints());
        questionInfoResp.setSource(abstractQuestion.getSource());
        questionInfoResp.setScore(abstractQuestion.getScore());
        if (question.getParentId() != null && question.getParentId() != 0) {
            Question parentQuestion = new Question().selectById(question.getParentId());
            AbstractQuestion parentAbstractQuestion = QuestionFactory.createQuestion(parentQuestion);
            parentAbstractQuestion.initKnowledgePoints();
            questionInfoResp.setKnowledgePoints(parentAbstractQuestion.getKnowledgePoints());
            questionInfoResp.setDifficultyLevel(String.valueOf(parentQuestion.getDifficultyLevel()));
            questionInfoResp.setSource(parentQuestion.getOfficialQuestionSource());
        }
        return questionInfoResp;
    }

    @Override
    public void doQuestion(List<DoQuestionReq> doQuestionReqs) {
        long userId = UserContextHolder.getUserId();
        ValidationUtils.throwIfEmpty(doQuestionReqs, "题目不能为空");
        DoQuestionReq last = doQuestionReqs.getLast();
        AbstractQuestionSet questionSet = QuestionSetFactory.of(last.getQuestionSetId());
        ValidationUtils.throwIfEmpty(questionSet, "题目集不存在");
        ValidationUtils.throwIfEmpty(questionSet.getQuestionSet(), "题目集不存在");
        //处理题目
        List<CompletableFuture<UserDoQuestion>> userDoQuestionsFutures = doQuestionReqs.stream()
            .map(doQuestionReq -> CompletableFuture.supplyAsync(() -> doQuestion(doQuestionReq, questionSet
                .getQuestionSet()
                .getId(), userId, questionSet.getQuestionSet().getTitle())))
            .toList();
        List<UserDoQuestion> userDoQuestions = userDoQuestionsFutures.stream().map(CompletableFuture::join).toList();
        iUserQuestionService.saveUserQuestion(userDoQuestions, last.getIndex(), questionSet);
        userDoQuestions.stream()
            .filter(userDoQuestion -> Objects.equals(userDoQuestion.getProblemState(), ProblemStateEnum.WRONG
                .getCode()))
            .forEach(userDoQuestion -> {
                addToWrongBook(userDoQuestion.getQuestionId(), userId, userDoQuestion.getQuestionSetId(), questionSet
                    .getQuestionSet()
                    .getTitle());
            });
    }

    protected UserDoQuestion doQuestion(DoQuestionReq doQuestionReq, Long questionSetId, long userId, String title) {
        Question question = new Question().selectById(doQuestionReq.getQuestionId());
        AbstractQuestion abstractQuestion = QuestionFactory.createQuestion(question);
        ValidationUtils.throwIfEmpty(abstractQuestion, "题目不存在");
        AbstractQuestion.CorrectResult result = abstractQuestion.correct(doQuestionReq.getUserAnswer());
        //保存答案
        UserDoQuestion userDoQuestion = new UserDoQuestion();
        userDoQuestion.setQuestionId(doQuestionReq.getQuestionId());
        userDoQuestion.setQuestionSetId(questionSetId);
        userDoQuestion.setUserId(userId);
        userDoQuestion.setQuestionType(question.getType());
        userDoQuestion.setUserAnswer(doQuestionReq.getUserAnswer());
        userDoQuestion.setUserAnswerType(doQuestionReq.getType());
        userDoQuestion.setDoTime(doQuestionReq.getDoTime());
        userDoQuestion.setProblemState(result.getProblemState());
        if (userDoQuestion.getProblemState().equals(ProblemStateEnum.WRONG.getCode())) {
            userDoQuestion.setScore(0.0);
        } else if (userDoQuestion.getProblemState().equals(ProblemStateEnum.RIGHT.getCode())) {
            userDoQuestion.setScore(question.getScore());
        }
        return userDoQuestion;
    }

    @Override
    public void correct(DoQuestionReq doQuestionReq, Long userId, String comment, Double score) {
        AbstractQuestionSet questionSet = QuestionSetFactory.of(doQuestionReq.getQuestionSetId());
        if (questionSet == null) {
            return;
        }
        UserDoQuestion userDoQuestion = doQuestion(doQuestionReq, questionSet.getQuestionSet()
            .getId(), userId, questionSet.getQuestionSet().getTitle());
        userDoQuestion.setComments(comment);
        userDoQuestion.setScore(score);
        iUserQuestionService.saveUserQuestion(List.of(userDoQuestion), doQuestionReq.getIndex(), questionSet);
    }

    @Override
    public void addToWrongBook(Long questionId, Long userId, Long questionSetId, String ext) {
        UserDoQuestion userDoQuestion = iUserQuestionService.getDoQuestionInfo(questionSetId, userId, questionId);
        if (userDoQuestion == null) {
            AbstractQuestionSet questionSet = QuestionSetFactory.of(questionSetId);
            if (questionSet == null) {
                return;
            }
            questionSetId = questionSet.getQuestionSet().getId();
            userDoQuestion = iUserQuestionService.getDoQuestionInfo(questionSet.getQuestionSet()
                .getId(), userId, questionId);
            if (userDoQuestion == null) {
                return;
            }
        }
        //添加到错题集合
        AbstractQuestionSet questionSet = QuestionSetFactory.of(userId, QuestionSetTypeEnum.WRONG_QUESTION.getCode());
        QuestionExt questionExt = new QuestionExt();
        questionExt.setFromName(ext);
        questionExt.setFromId(String.valueOf(questionSetId));
        questionExt.setUserAnswer(userDoQuestion.getUserAnswer());
        questionExt.setType(userDoQuestion.getUserAnswerType());
        questionSet.addQuestion(questionSet.getQuestionSet().getId(), questionId, questionSetId, JSON
            .toJSONString(questionExt));
        //重置这个题为未掌握
        questionSet.initQuestion(questionId);
    }

    @Override
    public void clearQuestionSetRecord(Long questionSetId) {
        AbstractQuestionSet questionSet = QuestionSetFactory.of(questionSetId);
        if (questionSet == null) {
            return;
        }
        iUserQuestionService.clearQuestionSetRecord(questionSet.getQuestionSet().getId(), UserContextHolder
            .getUserId());
    }
}
